/*
#Copyright (c) 2013, Philippe Bordron <philippe.bordron@gmail.com>
#
# This file is part of SIPPER.
#
# DCC is free software: you can redistribute it and/or modify
# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DCC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU LESSER GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# along with SIPPER.  If not, see <http://www.gnu.org/licenses/>
*/
package combi.wip.sipper.modeling.genomes;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import combi.wip.sipper.modeling.Protein;

public abstract class Genome<G extends Gene<E>, E extends Protein> extends ArrayList<Gene<E>> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Map<Gene<E>, Integer> rank;
	private Map<E, Collection<Gene<E>>> proteinToGenes;
	private Map<String, Gene<E>> idToGene;

	public Genome(List<G> genesSequence)
	{
		super(genesSequence);
		rank = new HashMap<Gene<E>, Integer>();
		proteinToGenes = new HashMap<E, Collection<Gene<E>>>();
		idToGene = new HashMap<String, Gene<E>>();
		int r = 0;
		for (Gene<E> g : genesSequence)
		{
			rank.put(g, r);
			r++;
			setIDGene(g ,g.getId());
			for (E protein : g.getProducts())
			{
				this.addMapEToG(proteinToGenes, protein, g);
			}
		}
	}

	private void addMapEToG(Map<E, Collection<Gene<E>>>map, E protein, Gene<E> g)
	{
		Collection<Gene<E>> genes = map.get(protein);
		if (genes == null)
		{
			genes = new HashSet<Gene<E>>();
			map.put(protein, genes);
		}
		genes.add(g);
	}
	
	public int getRank(G gene)
	{ 
		Integer result =  rank.get(gene);
		if (result != null)
		{
			return result;
		}
		return -1;
	}

	public Collection<Integer> getRanks(Collection<G> genes)
	{
		ArrayList<Integer> ranks = new ArrayList<Integer>(genes.size());
		for (G g : genes)
		{
			ranks.add(this.getRank(g));
		}
		return ranks;
	}
	
	public Collection<Gene<E>> getGenes(Protein enz)
	{
		Collection<Gene<E>> result = proteinToGenes.get(enz);
		if (result== null)
		{
			result = new HashSet<Gene<E>>();
		}
		return result;
	}

	public Gene<E> getGene(String id)
	{
		return idToGene.get(id);
	}
	
	public void setIDGene(Gene<E> g ,String id)
	{
		idToGene.put(id, g);
	}
	
	public Collection<E> getProductSet()
	{
		return new HashSet<E>(proteinToGenes.keySet());
	}
	

	public abstract List<Gene<E>> smallestInducedIntervalOfGenes(Collection<G> genes);

	public abstract double sizeOfSmallestInducedIntervalOGenes(Collection<G> genes);

	public void clear()
	{
		super.clear();
		rank.clear();
	}
	
}
